#pragma once

#include<iostream>
#include<unistd.h>
#include<string>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

using std::cout;
using std::endl;

const std::string comPath = "./myNamedPipe";

enum WHO
{
    //文件操作符的默认值
    defaultFd = -1,

    //标识调用者的身份
    sever = 0,
    client = 1,

    //读取namedPipe的一次读入数据的大小：bytes
    BaseSize = 4096
};

//管理命名管道的类，不同的身份的人调用会产生不同的效果
//serer管理命名管道的生命周期,client只负责使用管道
class NamedPipe
{
private:
    bool OpenNamedPipe(int openstyle)
    {
        //把得到的fd交给成员变量_fd即可
        _fd = open(comPath.c_str(),openstyle);
        if(_fd < 0)
        {
            perror("open namedpipe fail!");
            exit(1);
        }
        return true;
    }
public:

    NamedPipe(const std::string& path,int who)
        :_pipePath(path)
        ,_who(who)
        ,_fd(defaultFd)
    {
        //sever需要创建命名管道
        //cilent则什么都不需要做
        if(who == sever)
        {
            int res = mkfifo(comPath.c_str(),0666);
            if(res < 0)
            {
                perror("sever mkfifo fail!");
                exit(1);
            }
            cout<<"sever mkfifo success!"<<endl;
        }
    }

    bool OpenForRead()
    {
        return OpenNamedPipe(O_RDONLY);
    }

    bool OpenForWrite()
    {
        return OpenNamedPipe(O_WRONLY);
    }

    //通过stl的string为载体来写入，s为输入型参数
    int Write(const std::string &s)
    {
        int res = write(_fd,s.c_str(),s.size());
        //如果出错，打印错误信息，终止进程
        //如果正确，返回写入数据的字节数
        if(res < 0)
        {
            perror("read fail!");
            exit(1);
        }
        return res;
    }

    //通过stl的string为载体来输出，s为输出型参数
    int Read(std::string *s)
    {
        char buf[BaseSize] = {0};
        int res = read(_fd,buf,BaseSize);

        *s = buf;

        //如果出错，打印错误信息，终止进程
        //如果正确，返回读取的数据的字节数
        if(res < 0)
        {
            perror("read fail!");
            exit(1);
        }
        return res;
    }

    ~NamedPipe()
    {
        if(_who == sever)
        {
            int res = unlink(comPath.c_str());
            if(res < 0)
            {
                perror("unlink fail!");
                exit(1);
            }

            if(_fd != defaultFd)
            {
                close(_fd);
            }
        }
    }

private:
    const std::string _pipePath;//命名管道的路径，便于不同进程找到命名管道
    int _who;//身份
    int _fd;//namedpipe的文件描述符
};